package com.longg.dao.base;

import com.longg.annotation.MyField;
import com.longg.annotation.MyTable;
import com.longg.model.User;
import com.longg.model.UserInfo;
import com.longg.utils.JDBCUtil;
import com.mysql.cj.x.protobuf.MysqlxDatatypes;
import org.apache.commons.dbutils.BasicRowProcessor;
import org.apache.commons.dbutils.GenerousBeanProcessor;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class BaseDao<T> {
    private final Class<T> aClass;
    private final String tableName;
    private final String key;

    public BaseDao(Class<T> aclass){
        this.aClass = aclass;
        MyTable annotation = aClass.getAnnotation(MyTable.class);
        if(null != annotation){
            tableName = annotation.value();
            key = annotation.key();
        }else {
            tableName = "";
            key = "id";
        }
    }

    public List<T> findByCol(String colName, String value) {
        String sql = "select * from " + tableName + " where " + colName + " = ?";
        QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
        List<T> list = null;
        try {
            list = queryRunner.query(sql,new BeanListHandler<>(aClass),value);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return list;
    }

    public List<T> findByCols(String connect, Map<String, Object> colMap) {
        QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
        StringBuilder sb = new StringBuilder();
        sb.append("select * from " + tableName + " where ");
        if(colMap.isEmpty()){
            sb.delete(sb.lastIndexOf("where"),sb.length());
        }
        Set<String> keySet = colMap.keySet();
        for(String key : keySet){
            sb.append(key + "='" + colMap.get(key) + "' " + connect + " ");
        }
        sb.delete(sb.lastIndexOf(connect),sb.length());
        List<T> list = null;
        try {
            list = queryRunner.query(sb.toString(),new BeanListHandler<>(aClass));
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return list;
    }

    public int save(Object object){
        int res = 0;
        try {
            StringBuilder sb = new StringBuilder();
            QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
            sb.append("insert into " + tableName + " values(");
            Field[] fields = aClass.getDeclaredFields();
            Object[] params = new Object[fields.length];
            String methodName = null;
            for(int i = 0;i < fields.length;i++) {
                sb.append("?,");
                methodName = "get" + fields[i].getName().substring(0,1).toUpperCase() + fields[i].getName().substring(1);
                Method method = aClass.getDeclaredMethod(methodName);
                params[i] = method.invoke(object);
            }
            sb.delete(sb.lastIndexOf(","),sb.length());
            sb.append(")");
            res = queryRunner.update(sb.toString(), params);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return res;
    }

    public int update(Object object){
        int res = 0;
        StringBuilder sb = new StringBuilder();
        QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
        sb.append("update " + tableName + " set ");
        Field[] declaredFields = aClass.getDeclaredFields();
        Object[] param = new Object[declaredFields.length + 1];
        try {
            for (int i = 0; i < declaredFields.length; i++) {
                Field field = declaredFields[i];
                String fieldName = field.getName();
                String methodName = "get" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
                Method method = aClass.getDeclaredMethod(methodName);
                Object obj = method.invoke(object);
                param[i] = obj;
                MyField myField = field.getAnnotation(MyField.class);
                if(myField != null){
                    fieldName = myField.value();
                }
                if(fieldName.equals(key)){
                    param[declaredFields.length] = obj;
                }
                sb.append(fieldName + " = ?,");

            }
            sb.delete(sb.lastIndexOf(","),sb.length());
            sb.append(" where " + key + " = ?");
            res = queryRunner.update(sb.toString(), param);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return res;
    }

    public T findById(Object id) {
        String sql = "select * from " + tableName + " where " + key + " = ?";
        QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
        T query = null;
        BasicRowProcessor basicRowProcessor = new BasicRowProcessor(new GenerousBeanProcessor());
        try {
            query = queryRunner.query(sql, new BeanHandler<>(aClass,basicRowProcessor),id);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return query;
    }

    public int deleteById(Object id) {
        String sql = "delete from " + tableName + " where " + key + " = ?";
        QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
        int query = 0;
        try {
            query = queryRunner.update(sql,id);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return query;
    }

    public long saveRId(Object object){
        int res = 0;
        try {
            StringBuilder sb = new StringBuilder();
            QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
            sb.append("insert into " + tableName + " values(");
            Field[] fields = aClass.getDeclaredFields();
            Object[] params = new Object[fields.length];
            String methodName = null;
            for(int i = 0;i < fields.length;i++) {
                sb.append("?,");
                methodName = "get" + fields[i].getName().substring(0,1).toUpperCase() + fields[i].getName().substring(1);
                Method method = aClass.getDeclaredMethod(methodName);
                params[i] = method.invoke(object);
            }
            sb.delete(sb.lastIndexOf(","),sb.length());
            sb.append(")");
            Object insert = queryRunner.insert(sb.toString(), new ScalarHandler<>(), params);
            res = Integer.parseInt(insert.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return res;
    }
}
